package org.opens.mybatisplus.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import org.opens.mybatisplus.pojo.dto.MyBatisPerson;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

public interface MybatisPersonService {

    /**
     * 功能:
     *      使用Optional来包装dao层的返回对象.
     */
    public List<MyBatisPerson> findByIds(List<Integer> ids);

    public MyBatisPerson findById(Integer id) throws Exception;

    public Optional<MyBatisPerson> findByIdUseRedisCache(Integer id);

    public Optional<MyBatisPerson.Count> countAll();

    /**
     * 功能:
     *      实现了使用BaseCount作为统计类的公共类, 其实可以做成抽象类, 但是做成抽象类就不能使用@Data注解了.
     * 说明:
     *      1. service层返回值不适合为Optional, 因为Optional的作用是用来避免null, 其实类似于spring cloud中的熔断机制, 使用到service层的话相当于是统计失败时给定一个初始值;
     *          - 所以, service层的返回值不适合为Optional, 而应该为具体的类型, 但是要自己保证Optional封装的类不为null, 就可以不判断null.
     * @return  统计结果
     */
    public MyBatisPerson.Count2 countAll2();

    /**
     * 功能:
     *      根据传入的实体类的函数, 将List转换为Map, key为传入的函数的返回值, value在这里是直接写死的MyBatisPerson
     * @param function  实体类的方法, serviceImpl中的代码会根据这个方法的返回值作为key将List转换为Map.
     * @param <T>       key的类型, 由于不确定规定为了泛型.
     * @return          转换后的Map.
     */
    public <T> Map<T, MyBatisPerson> findAll_useFunctionToMap(Function<MyBatisPerson, T> function);

    /**
     * 功能:
     *      这个方法是直接将key生成函数传入, 将value的生成也传入.
     * 说明:
     *      1. 这种方式的好处是极大的融合了代码, 这一个方法就可以实现将List<MyBatisPerson>转换为各种Map; 减少了代码量.
     *      2. 缺点:
     *          - 自定义转换规则后, 就无法通过findUsages功能来查找这个方法在哪里被使用了, 在传统方法中, 只需要看到这个方法就可以知道这个方法的功能, 但是在引入这种语法之后, 一个方法
     *          可以面向多种作用, 就会使代码的耦合性变高.
     *              1. 但是可读性并没有变差, 因为lambda直接在调用出直接声明了转换规则.
     * 注意:
     *      1. 该方法虽然即为灵活, 但是确实如果多个不同功能的方法都经由这个方法实现, 会使程序结构混乱, 可以对这个方法进行一次二次封装.
     *          - 可以将这个方法修饰为private.
     * @param keyFunctioon      生成key的Function
     * @param valueFunctioon    生成value的Function
     * @param <K>               key的泛型
     * @param <V>               value的泛型
     * @return                  Map<K, V>
     */
    public <K, V> Map<K, V> findAll_useFunctionToMap(Function<MyBatisPerson, K> keyFunctioon, Function<MyBatisPerson, V> valueFunctioon);

    /**
     * 功能:
     *      这个方法太过灵活, 不适合对外开放, 因为会造成程序结构混乱(无法通过函数名称来查找这个函数的功能).
     *
     * @param list              被转换的对象
     * @param keyFunctioon      生成key的Function
     * @param valueFunctioon    生成value的Function
     * @param <K>               key的类型
     * @param <V>               value的类型
     * @return                  Map<K, V>
     */
    public <K, V> Map<K, V> translateToMap(List<MyBatisPerson> list, Function<MyBatisPerson, K> keyFunctioon, Function<MyBatisPerson, V> valueFunctioon);

    /**
     * 功能:
     *      将List转换为Map
     */
    public Map<Integer, MyBatisPerson> findMap_useIdIsKey_byIds(List<Integer> ids);

    public Integer insertAndReturnId(MyBatisPerson myBatisPerson);

    /**
     * 功能:
     *      使用mysql的ON DUPLICATE KEY UPDATE实现批量更新.
     * 执行的sql:
     *      INSERT INTO mybatis_person ( id, name_value, old, ek_address ) VALUES (1, 'x1test', 31, 's1') , (2, 'x2', 32, 's2') , (3, 'x3', 33, 's3')
     *      ON DUPLICATE KEY UPDATE name_value = VALUES( name_value ), old = VALUES( old ), ek_address = VALUES( ek_address )
     * 说明:
     *      1. 批量更新很好用, 适用于将配置属性动态存于表中而不是定义在表列上所进行的更新.
     */
    public void batchUpdate(List<MyBatisPerson> personList);

    /**
     * 功能:
     *      使用replace实现和ON DUPLICATE KEY UPDATE一样的功能.
     * 执行的sql:
     *      REPLACE into mybatis_person(`id`, `name_value`, `old`, `ek_address`) VALUES (1, 'x1testtest', 60, 's2') , (2, 'x2', 60, 's2') , (3, 'x3', 60, 's3')
     */
    public void batchUpdate2(List<MyBatisPerson> personList);

    /**
     * 功能:
     *      使用mybatis的trim标签进行模拟where标签.
     * 说明:
     *      1. 最终的sql会根据参数的不同而不同.
     *          - 如果只有nameValue参数, 则最终的sql为: `select id, name_value, old, ek_address FROM mybatis_person mp where mp.old <= 20 `;
     *          - 如果有nameValue和old参数, 则最终的sql为: `select id, name_value, old, ek_address FROM mybatis_person mp where mp.name_value like 'x%' and mp.old <= 20 `;
     */
    public List<MyBatisPerson> useTrimQuery(MyBatisPerson myBatisPerson);

    /**
     * 功能:
     *      使用mybatis的bind标签进行查询.
     * 说明:
     *      1. 使用mybatis的bind标签进行参数处理.
     *          - 如果传入的nameValue参数不为null或者'', 最终的sql: `select id, name_value, old, ek_address FROM mybatis_person mp WHERE mp.name_value like 'x%'`;
     *          - 如果传入的nameValue参数为null或者'', 最终的sql: `select id, name_value, old, ek_address FROM mybatis_person mp`;
     */
    public List<MyBatisPerson> useBindQuery(MyBatisPerson myBatisPerson);

    public void deleteById(Integer id) throws Exception;

    public void update(MyBatisPerson person);

    public IPage<MyBatisPerson> pageOfCondition(Integer pageNumber, Integer pageSize, MyBatisPerson person);

}
